package org.dlow.annotation;

import org.springframework.stereotype.Component;
import org.dlow.common.constants.FaultTolerant;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.concurrent.TimeUnit;

import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.ElementType.TYPE;

/**
 * @RpcService - RPC服务发布注解(服务端使用)
 * 
 * <p>该注解用于在服务端标记需要发布为RPC服务的实现类。
 * 框架会自动扫描标记了此注解的类,将其注册到注册中心,供客户端调用。
 * 
 * <h3>核心功能:</h3>
 * <ul>
 *   <li>自动将服务注册到注册中心(如Zookeeper)</li>
 *   <li>支持服务版本管理</li>
 *   <li>支持一个实现类实现多个接口时指定发布的接口</li>
 *   <li>将服务实例缓存到本地,供后续调用使用</li>
 * </ul>
 * 
 * <h3>使用示例:</h3>
 * <pre>
 * // 最简单的使用方式,默认发布第一个实现的接口
 * &#64;Component
 * &#64;RpcService
 * public class UserServiceImpl implements UserService {
 *     
 *     &#64;Override
 *     public User getUserById(Long id) {
 *         // 业务逻辑...
 *         return user;
 *     }
 * }
 * 
 * // 指定版本号
 * &#64;Component
 * &#64;RpcService(version = "2.0")
 * public class UserServiceV2Impl implements UserService {
 *     // 新版本的实现...
 * }
 * 
 * // 实现多个接口时,指定发布哪个接口
 * &#64;Component
 * &#64;RpcService(serviceInterface = OrderService.class)
 * public class OrderServiceImpl implements OrderService, Serializable {
 *     // 只发布OrderService接口,不发布Serializable
 * }
 * </pre>
 * 
 * <h3>工作原理:</h3>
 * <ol>
 *   <li>ProviderPostProcessor后置处理器扫描所有Bean</li>
 *   <li>发现标记了@RpcService的Bean</li>
 *   <li>解析服务接口名称(默认取第一个接口,或使用serviceInterface指定)</li>
 *   <li>构造服务URL(包含IP、端口、服务名、版本号等信息)</li>
 *   <li>将服务URL注册到注册中心</li>
 *   <li>将服务实例缓存到本地Map中,key为"服务名:版本号"</li>
 *   <li>当客户端调用时,根据key从缓存中获取服务实例并执行方法</li>
 * </ol>
 * 
 * <h3>注意事项:</h3>
 * <ul>
 *   <li><b>必须配合@Component使用</b>,让Spring能够扫描并创建Bean</li>
 *   <li>如果一个类实现了多个接口,默认发布第一个接口,可通过serviceInterface指定</li>
 *   <li>version用于区分同一接口的不同实现,客户端需指定相同版本号才能调用</li>
 *   <li>不直接使用@Component是为了不依赖Spring,但实际使用时仍需配合@Component</li>
 * </ul>
 * 
 * <h3>为什么不直接使用@Component?</h3>
 * <p>设计上是为了让RPC框架不强依赖Spring,保持框架的独立性。
 * 但在实际SpringBoot项目中使用时,仍然需要配合@Component使用,
 * 因为需要让Spring创建Bean实例后,ProviderPostProcessor才能扫描和处理。
 * 
 * @description: 服务端服务发布注解,自动注册服务到注册中心
 * @Author: 山沐与山
 * @CreateTime: 2024-05-15 11:30
 * @see ProviderPostProcessor 处理此注解的后置处理器
 * @see org.dlow.register.ServiceRegistry 注册中心服务
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(value={TYPE})
public @interface RpcService {

    /**
     * 指定要发布的服务接口
     * <p>当一个实现类实现了多个接口时,需要通过此属性指定发布哪个接口作为RPC服务。
     * 如果不指定,默认发布实现的第一个接口。
     * 
     * <p>使用场景示例:
     * <pre>
     * // UserServiceImpl实现了UserService和Serializable两个接口
     * // 我们只想发布UserService,不想发布Serializable
     * &#64;RpcService(serviceInterface = UserService.class)
     * public class UserServiceImpl implements UserService, Serializable {
     *     // ...
     * }
     * </pre>
     * 
     * @return 服务接口Class,默认为void.class(表示使用第一个接口)
     */
    Class<?> serviceInterface() default void.class;

    /**
     * 服务版本号
     * <p>用于区分同一个服务接口的不同版本实现。
     * 
     * <p>版本号的使用场景:
     * <ul>
     *   <li>灰度发布: 新旧版本同时存在,通过版本号区分</li>
     *   <li>API升级: 保留旧版本API的同时提供新版本</li>
     *   <li>A/B测试: 不同版本的实现用于测试对比</li>
     * </ul>
     * 
     * <p>客户端必须指定相同的版本号才能调用对应版本的服务。
     * 
     * @return 版本号,默认为"1.0"
     */
    String version() default "1.0";
}
